﻿using LSFTP.model;
using Rainbow.common.comparer;
using Rainbow.core;
using Rainbow.model;
using Rainbow.model.dataConversion;
using Rainbow.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data.OleDb;
using System.Data.SQLite;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;


namespace Rainbow.view.dataConversion
{
    /// <summary>
    /// DataConversionDlg.xaml 的交互逻辑
    /// </summary>
    public partial class DataConversionDlg : Window
    {
        private DataConversionDlgViewModel windowViewModel;
        private object lvPath_PreviewDragOver;
        private object lvPath_Drop;

        public DataConversionDlg()
        {
            InitializeComponent();

            windowViewModel = new DataConversionDlgViewModel();
            this.DataContext = windowViewModel;

            this.Closing += new System.ComponentModel.CancelEventHandler(Window_Closing);

            this.btnOK.Click += new RoutedEventHandler(OK_Click);
            this.btnCancel.Click += new RoutedEventHandler(Cancel_Click);

            this.tvPath.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(Path_SelectedItemChanged);
            this.tvPath.PreviewMouseUp += new MouseButtonEventHandler(tvPath_PreviewMouseUp);

            this.lvPath.SelectionChanged += new SelectionChangedEventHandler(lvPath_SelectionChanged);
            //this.lvPath.MouseDoubleClick += new System.Windows.Input.MouseButtonEventHandler(lvPath_MouseDoubleClick);
            this.lvPath.PreviewMouseDoubleClick += new MouseButtonEventHandler(lvPath_MouseDoubleClick);

            this.toolPrevious.Click += new RoutedEventHandler(Previous_Click);

        }

        private void Previous_Click(object sender, RoutedEventArgs e)
        {
            // 判断目录树是否有被选中节点，没有则退出
            if (this.tvPath.SelectedItem == null) return;

            // 将控件选中的节点转换未PathTreeNode类型
            LocalPathTreeNode curNode = this.tvPath.SelectedItem as LocalPathTreeNode;
            if (curNode == null) return;  // 如果转换失败，直接退出

            if(curNode.ParentNode == null) return;

            curNode.IsSelected = false;
            curNode.ParentNode.IsSelected = true;

            RefreshListView(curNode.ParentNode);

        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (!isStop)
            {
                MessageBoxResult result = System.Windows.MessageBox.Show("正在进行数据转换，是否停止转变并关闭窗口？", "关闭确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
                if (result == MessageBoxResult.No)
                {
                    e.Cancel = true;
                    return;
                }
            }
            isStop = true;
        }

        private void Path_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            LocalPathTreeNode node = this.tvPath.SelectedItem as LocalPathTreeNode;
            if(node == null) return;
            windowViewModel.curPathNode = node;
            if(node.ParentNode == null)
            {
                windowViewModel.rootPathNode = node;
            }
        }

        private void tvPath_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            // 判断是不是点击的TextBlock(判断点击的是展开折叠按钮还是文本）
            ToggleButton toggleButton = e.OriginalSource as ToggleButton;
            if (toggleButton != null) return;

            System.Windows.Controls.TreeView tv = sender as System.Windows.Controls.TreeView;
            if (null == tv) return;
            if (tv.SelectedItem == null) return;

            LocalPathTreeNode node = tv.SelectedItem as LocalPathTreeNode;

            if (node == null) return;

            FrameworkElement rootElement = (FrameworkElement)lvPath;
            System.Windows.Controls.CheckBox checkBox = FindVisualChild<System.Windows.Controls.CheckBox>(rootElement, "cbAllSelected");

            if (checkBox != null)
            {
                checkBox.IsChecked = false;
            }

            RefreshListView(node);
        }

        // 方法来获取文件名和大小
        private List<FileInfo> GetFilesInfo(string directoryPath)
        {
            List<FileInfo> res = new List<FileInfo>();
            // 检查目录是否存在
            if (!Directory.Exists(directoryPath))
            {
                Console.WriteLine("Directory does not exist: " + directoryPath);
                return res;
            }

            // 获取目录中的所有文件
            FileInfo[] files = new DirectoryInfo(directoryPath).GetFiles();
            foreach (FileInfo file in files)
            {
                res.Add(file);
            }
            return res;
        }

        private List<DirectoryInfo> GetDirectoryInfos(string directoryPath)
        {
            List<DirectoryInfo> res = new List<DirectoryInfo>();

            // 检查目录是否存在
            if (!Directory.Exists(directoryPath))
            {
                Console.WriteLine("Directory does not exist: " + directoryPath);
                return res;
            }

            DirectoryInfo[] infos = new DirectoryInfo(directoryPath).GetDirectories();
            foreach(DirectoryInfo info in infos)
            {
                res.Add(info);
            }
            return res;
        }

        /// <summary>
        /// 根据树节点刷新文件列表
        /// </summary>
        /// <param name="node"></param>
        private void RefreshListView(LocalPathTreeNode node)
        {
            if (node == null) return;

            // 清空文件列表
            windowViewModel.CurPaths.Clear();
            try
            {
                ObservableCollection<model.FileInfoViewModel> infos = new ObservableCollection<model.FileInfoViewModel>();
                List<DirectoryInfo> directoryInfos = GetDirectoryInfos(node.path);
                foreach(DirectoryInfo info in directoryInfos)
                {
                    infos.Add(new FileInfoViewModel(info));
                }

                List<FileInfo> files = GetFilesInfo(node.path);
                foreach (FileInfo file in files)
                {
                    infos.Add(new model.FileInfoViewModel(file));
                }
                windowViewModel.CurPaths = new ObservableCollection<model.FileInfoViewModel>(infos.OrderByDescending(item => item.IsDirectory));
            }
            catch (Exception)
            {

            }
        }

        // 辅助方法，用于在VisualTree中查找控件
        public static T FindVisualChild<T>(DependencyObject obj, string name) where T : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child is T && (((T)child).GetValue(NameProperty) as string) == name)
                {
                    return (T)child;
                }
                else
                {
                    T childOfChild = FindVisualChild<T>(child, name);
                    if (childOfChild != null)
                    {
                        return childOfChild;
                    }
                }
            }
            return null;
        }


        private void lvPath_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            foreach (model.FileInfoViewModel item in e.RemovedItems)
            {
                item.IsSelected = false;
            }
            foreach (model.FileInfoViewModel item in e.AddedItems)
            {
                item.IsSelected = true;
            }
        }

        private void lvPath_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            System.Windows.Controls.ListView listView = sender as System.Windows.Controls.ListView;
            model.FileInfoViewModel item = listView.SelectedItem as model.FileInfoViewModel;
            if (item != null)
            {
                if (item.IsDirectory)
                {
                    
                    try
                    {
                        ObservableCollection<model.FileInfoViewModel> infos = new ObservableCollection<model.FileInfoViewModel>();
                        List<DirectoryInfo> directoryInfos = GetDirectoryInfos(item.FullName);
                        foreach (DirectoryInfo info in directoryInfos)
                        {
                            infos.Add(new FileInfoViewModel(info));
                        }
                        List<FileInfo> files = GetFilesInfo(item.FullName);
                        foreach (FileInfo file in files)
                        {
                            infos.Add(new model.FileInfoViewModel(file));
                        }

                        var sortedList = infos.OrderBy(vm => vm, new NaturalFileInfoViewModelComparer()).ToList();

                        windowViewModel.CurPaths.Clear();
                        windowViewModel.CurPaths = new ObservableCollection<model.FileInfoViewModel>(sortedList.OrderByDescending(v => v.IsDirectory));                     

                        FrameworkElement rootElement = (FrameworkElement)lvPath;
                        System.Windows.Controls.CheckBox checkBox = FindVisualChild<System.Windows.Controls.CheckBox>(rootElement, "cbAllSelected");

                        if (checkBox != null)
                        {
                            checkBox.IsChecked = false;
                        }

                        SetTreeSelectNode(item.FullName);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }
        }
        private void SetTreeSelectNode(string FullName)
        {

                foreach (var item in windowViewModel.TreeNodes)
                {
                    if (FullName.StartsWith(item.path))
                    {
                        item.IsExpanded = true;
                        int index = item.Name.Split('\\').Length - 1;
                        if (item.Name.EndsWith("\\"))
                        {
                            index--;
                        }    
                        searchNode(item, FullName, index);
                        break;
                    }
                }
            

        }

        private void searchNode(LocalPathTreeNode node, string FullName, int index)
        {
            string[] names = FullName.Split('\\');
            if (node.path.Equals(FullName))
            {
                node.IsSelected = true;
                //windowViewModel.curPath = node.path;
                return;
            }
            if (index == names.Length - 1) return;

            index++;

            //node.LoadChildren();

            foreach (LocalPathTreeNode item1 in node.Children)
            {
                if (item1.Name!=null&&item1.Name.Equals(names[index]))
                {
                    item1.IsExpanded = true;
                    searchNode(item1, FullName, index);
                }
            }
        }

        List<ConversionFile> conversionFiles = new List<ConversionFile>();
        string folderPath = "";
        ProgressingDataAcqDlg conversionDlg;
        private object locker = new object();

        private void OK_Click(object sender, RoutedEventArgs e)
        {
            if(lvPath.SelectedItems.Count == 0)
            {
                System.Windows.MessageBox.Show("请先选择文件", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();

            // 显示文件夹选择对话框
            DialogResult result = folderBrowserDialog.ShowDialog();

            // 检查用户是否选择了文件夹
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                lock (locker)
                {
                    // 获取用户选择的文件夹路径
                    folderPath = folderBrowserDialog.SelectedPath;

                    conversionFiles.Clear();
                    List<string> folderPaths = new List<string>();
                    List<string> files = new List<string>();
                    foreach (FileInfoViewModel item in lvPath.SelectedItems)
                    {
                        if (item.IsDirectory)
                        {
                            folderPaths.Add(item.FullName);
                        }
                        else
                        {
                            if(item.Length > 0)
                            {
                                files.Add(item.FullName);
                                AddConversionFile(item.FullName);
                            }

                        }
                    }
                    // 调用方法以获取所有文件
                    List<FileInfo> allFiles = GetAllFiles(folderPaths);

                    // 输出文件名
                    foreach (FileInfo file in allFiles)
                    {
                        if (file.Length > 0)
                        {
                            files.Add(file.FullName);
                            AddConversionFile(file.FullName);
                        }
                    }
                }

                if(conversionFiles.Count == 0)
                {
                    System.Windows.MessageBox.Show("未检测到数据文件","提示",MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }

                isStop = false;
                progressBar.Minimum = 0;
                progressBar.Maximum = conversionFiles.Count;

                //conversionDlg = new ProgressingDataAcqDlg();
                //conversionDlg.windowViewModel.contents = "数据转换中...";
                //conversionDlg.progressBar.Minimum = 0;
                //conversionDlg.progressBar.Maximum = conversionFiles.Count;
                //conversionDlg.Owner = this;
                //conversionDlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                Thread thread = new Thread(new ThreadStart(ConversionThread));
                thread.Start();
                //conversionDlg.ShowDialog();
                progressBarGrid.Visibility = Visibility.Visible;
                this.btnOK.IsEnabled = false;
            }
            
        }

        private bool isStop = true;

        private void ConversionThread()
        {
            lock (locker)
            {
                Dictionary<int, DateTime> startTimes = new Dictionary<int, DateTime>();
                Dictionary<int, StreamWriter> writerDic = new Dictionary<int, StreamWriter>();
                Dictionary<int, ChannelData> channelDatas = new Dictionary<int, ChannelData>();
                try
                {
                    conversionFiles.Sort((c1, c2) => c1.dateTime.CompareTo(c2.dateTime));

                    foreach (var item in conversionFiles)
                    {
                        try
                        {
                            channelDatas.Clear();
                            SQLiteHelper sQLite = new SQLiteHelper(item.fullName);
                            sQLite.Open();
                            Tuple<bool, SQLiteDataReader, string> res = sQLite.ExecuteReader("select * from fbgdata order by chno,fbgno", null);
                            if (res.Item1) // 查询成功
                            {
                                using (res.Item2)
                                {
                                    while (res.Item2.Read())
                                    {

                                        int channelNo = int.Parse(res.Item2["chno"].ToString());
                                        int gratingNo = int.Parse(res.Item2["fbgno"].ToString());
                                        int rate = int.Parse(res.Item2["samplingrate"].ToString()); ;
                                        int dataLength = int.Parse(res.Item2["datalength"].ToString());

                                        byte[] bytes = (byte[])res.Item2["wave"];
                                        GratingData gratingData = new GratingData();
                                        gratingData.rate = rate;
                                        gratingData.dateLength = dataLength;
                                        gratingData.gratingNo = gratingNo;
                                        gratingData.datas = new double[bytes.Length / 4];
                                        for (int i = 0; i < bytes.Length; i += 4)
                                        {
                                            double value = BitConverter.ToSingle(bytes, i);
                                            gratingData.datas[i / 4] = value;
                                        }
                                        if (!channelDatas.ContainsKey(channelNo))
                                        {
                                            DateTime dateTime = item.dateTime.AddMilliseconds(-dataLength * (1000 / rate));
                                            ChannelData channelData = new ChannelData();
                                            channelData.channelNo = channelNo;
                                            channelData.dateTime = dateTime;
                                            channelData.dataLength = dataLength;
                                            channelData.rate = rate;
                                            channelData.gratingDatas = new List<GratingData>();
                                            channelDatas.Add(channelNo, channelData);
                                        }

                                        channelDatas[channelNo].gratingDatas.Add(gratingData);
                                    }
                                }
                            }
                            sQLite.Close();


                            // 写入文件
                            foreach (KeyValuePair<int, ChannelData> keyValuePair in channelDatas)
                            {
                                int channelNo = keyValuePair.Key;
                                ChannelData channelData = keyValuePair.Value;
                                channelData.gratingDatas.Sort((g1, g2) => g1.gratingNo.CompareTo(g2.gratingNo));

                                DateTime curTime = channelData.dateTime;
                                StringBuilder sb = new StringBuilder();
                                for (int i = 0; i < channelData.dataLength; i++)
                                {
                                    curTime = channelData.dateTime.AddMilliseconds((1000 / channelData.rate) * i);
                                    if (!startTimes.ContainsKey(channelNo))
                                    {
                                        startTimes.Add(channelNo, curTime.AddDays(-1));
                                    }
                                    if ((curTime - startTimes[channelNo]).TotalMilliseconds >= 30 * 60 * 1000)
                                    {
                                        startTimes[channelNo] = curTime;
                                        string fileName = folderPath + "\\" + curTime.ToString("yyyy-MM-dd HH-mm-ss") + " FileCan" + channelNo.ToString("D2") + ".txt";
                                        if (!writerDic.ContainsKey(channelNo))
                                        {
                                            StreamWriter sw = new StreamWriter(fileName);
                                            writerDic.Add(channelNo, sw);
                                        }
                                        else
                                        {
                                            writerDic[channelNo].Close();
                                            writerDic[channelNo] = new StreamWriter(fileName);
                                        }
                                    }

                                    sb.Clear();
                                    sb.Append(curTime.ToString("yyyy-MM-dd HH-mm-ss")).Append(" ").Append(channelNo.ToString("D2")).Append(" ");
                                    for (int j = 0; j < channelData.gratingDatas.Count; j++)
                                    {
                                        sb.Append(channelData.gratingDatas[j].datas[i].ToString("F3")).Append("  ");
                                    }

                                    writerDic[channelNo].WriteLine(sb.ToString());
                                }
                            }

                            App.Current.Dispatcher.InvokeAsync((Action)(() =>
                            {
                                //conversionDlg.progressBar.Value++;
                                progressBar.Value++;
                            }));

                            if (isStop)
                            {

                                foreach (KeyValuePair<int, StreamWriter> keyValuePair in writerDic)
                                {
                                    keyValuePair.Value.Close();
                                }
                                App.Current.Dispatcher.InvokeAsync((Action)(() =>
                                {
                                    progressBarGrid.Visibility = Visibility.Hidden;
                                    this.btnOK.IsEnabled = true;
                                    isStop = true;
                                }));
                                return;
                            }
                        }
                        catch (Exception)
                        {
                            
                        }

                    }

                    foreach (KeyValuePair<int, StreamWriter> keyValuePair in writerDic)
                    {
                        keyValuePair.Value.Close();
                    }

                }
                catch(Exception ex)
                {
                    foreach (KeyValuePair<int, StreamWriter> keyValuePair in writerDic)
                    {
                        keyValuePair.Value.Close();
                    }
                    App.Current.Dispatcher.InvokeAsync((Action)(() =>
                    {
                        progressBarGrid.Visibility = Visibility.Hidden;
                        this.btnOK.IsEnabled = true;
                        isStop = true;
                    }));
                    System.Windows.MessageBox.Show("转换失败：" + ex.Message,"错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
                    return;
                }

            }

            //App.Current.Dispatcher.InvokeAsync((Action)(() =>
            //{
            //    conversionDlg.Close();
            //}));

            System.Windows.MessageBox.Show("转换完成", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
            App.Current.Dispatcher.InvokeAsync((Action)(() =>
            {
                progressBarGrid.Visibility = Visibility.Hidden;
                this.btnOK.IsEnabled = true;
                isStop = true;
            }));
        }

        private void AddConversionFile(string filePath)
        {
            string extension = Path.GetExtension(filePath);
            if (!".ftms".Equals(extension))
            {
                return;
            }
            string name = Path.GetFileNameWithoutExtension(filePath);
            string[] _name = name.Split('_');
            string[] dateTimeSplit = _name[_name.Length - 1].Split('-');
            if (dateTimeSplit.Length != 7)
            {
                return;
            }
            string format = "yyyy-MM-dd HH:mm:ss.fff";
            string dateTimeStr = dateTimeSplit[0] + "-" + dateTimeSplit[1] + "-" + dateTimeSplit[2] + " " + dateTimeSplit[3] + ":" + dateTimeSplit[4] + ":" + dateTimeSplit[5] + "." + dateTimeSplit[6];
            ConversionFile file = new ConversionFile();
            file.name = Path.GetFileName(filePath);
            file.fullName = filePath;
            DateTime dateTime;
            DateTime.TryParseExact(dateTimeStr, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime);
            file.dateTime = dateTime;
            file.dateTimeStr = dateTimeStr;
            conversionFiles.Add(file);
        }

        // 方法：递归获取所有文件
        static List<FileInfo> GetAllFiles(List<string> folderPaths)
        {
            List<FileInfo> files = new List<FileInfo>();

            foreach (string folderPath in folderPaths)
            {
                // 检查目录是否存在
                if (Directory.Exists(folderPath))
                {
                    // 获取目录信息
                    DirectoryInfo dirInfo = new DirectoryInfo(folderPath);

                    // 获取所有文件
                    files.AddRange(dirInfo.GetFiles("*", SearchOption.AllDirectories));
                }
            }

            return files;
        }

        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            if (!isStop)
            {
                MessageBoxResult result = System.Windows.MessageBox.Show("正在进行数据转换，是否停止转变并关闭窗口？", "关闭确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
                if (result == MessageBoxResult.No) return;
            }
            isStop = true;
            this.Close();
        }

        private void cbAllSelected_Checked(object sender, RoutedEventArgs e)
        {
            lvPath.SelectedItems.Clear();
            foreach (model.FileInfoViewModel item in windowViewModel.CurPaths)
            {
                item.IsSelected = true;
                lvPath.SelectedItems.Add(item);
            }
        }

        private void cbAllSelected_Unchecked(object sender, RoutedEventArgs e)
        {
            lvPath.SelectedItems.Clear();
            foreach (model.FileInfoViewModel item in windowViewModel.CurPaths)
            {
                item.IsSelected = false;
            }
        }
    }

    public class DataConversionDlgViewModel : ViewModelBase
    {
        public DataConversionDlgViewModel()
        {
            CurPaths = new ObservableCollection<FileInfoViewModel>();
            TreeNodes = new ObservableCollection<LocalPathTreeNode>();
            // 获取桌面路径
            string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            LocalPathTreeNode RootNode = new LocalPathTreeNode();
            RootNode.displayName = "桌面";
            RootNode.Name = desktopPath;
            RootNode.path = desktopPath;
            TreeNodes.Add(RootNode);

            // 获取系统驱动器的根目录
            DriveInfo[] allDrives = DriveInfo.GetDrives();
            foreach (DriveInfo drive in allDrives)
            {
                if (drive.IsReady) // 确保驱动器已就绪
                {
                    RootNode = new LocalPathTreeNode();
                    RootNode.displayName = drive.Name.Replace(":\\","盘");
                    RootNode.Name = drive.Name;
                    RootNode.path = drive.Name;
                    TreeNodes.Add(RootNode);
                }
            }


        }

        private ObservableCollection<model.FileInfoViewModel> m_CurPaths;
        public ObservableCollection<model.FileInfoViewModel> CurPaths
        {
            get { return this.m_CurPaths; }
            set
            {
                this.m_CurPaths = value;
                NotifyPropertyChanged();
            }
        }


        private ObservableCollection<LocalPathTreeNode> m_TreeNodes;
        public ObservableCollection<LocalPathTreeNode> TreeNodes
        {
            get { return this.m_TreeNodes; }
            set
            {
                this.m_TreeNodes = value;
                NotifyPropertyChanged();
            }
        }

        private LocalPathTreeNode m_curPathNode;
        public LocalPathTreeNode curPathNode
        {
            get { return m_curPathNode; }
            set
            {
                m_curPathNode = value;
                if (value != null)
                {
                    curPath = curPathNode.path;
                }

                NotifyPropertyChanged();
            }
        }

        private LocalPathTreeNode m_rootPathNode;
        public LocalPathTreeNode rootPathNode
        {
            get { return m_rootPathNode; }
            set
            {
                m_rootPathNode = value;
                NotifyPropertyChanged();
            }
        }

        private string m_curPath;
        public string curPath
        {
            get { return m_curPath; }
            set
            {
                m_curPath = value;
                NotifyPropertyChanged();
            }
        }
    }
}
